﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using SOM.Model;
using OpenTK.Input;


namespace SOM.UI
{
    public partial class ResultForm : Form
    {
        bool loaded = false;
        private int _mouseStartX = 0;
        private int _mouseStartY = 0;
        private float angleX = 0;
        private float angleY = 0;
        private float angleXS = 0;
        private float angleYS = 0;
        private float distance = 1;
        private float distanceS = 5;
        private float rotSpeed = 0.1f;
        private SOMNetwork sofmnet;
        private Vector3d eye = new Vector3d(0, 0, 5);
        private Vector3d target = new Vector3d(0, 0, 0);
        private Vector3d up = new Vector3d(0, 1, 0);
        private bool animating = false;

        public ResultForm(SOMNetwork sofm)
        {
            InitializeComponent();
            this.sofmnet = sofm;
            sofm.computeneuroncolors();
            populateSequenceTreeView();
            populateVertexTreeView();
            this.textBoxQE.Text = this.sofmnet.QuantizationError.ToString();
            this.textBoxTotSeq.Text = this.sofmnet.CompositionalSpectrum.CSVectorList.Count.ToString();
            this.textBoxTotVert.Text = this.sofmnet.NetworkNeuronList.Count.ToString();
        }

        private void populateSequenceTreeView()
        {
            foreach (var cvector in sofmnet.CompositionalSpectrum.CSVectorList)
            {
                TreeNode treeNode = new TreeNode(cvector.SequenceName);
                treeNode.BackColor = Color.FromArgb(cvector.R, cvector.G, cvector.B);
                treeViewSeqList.Nodes.Add(treeNode);
            }
        }

        private void populateVertexTreeView()
        {
            int vernum = 0;
            foreach (var neuron in sofmnet.NetworkNeuronList)
            {
                TreeNode treeNode = new TreeNode("Vertex-" + vernum);
                treeNode.Name = vernum.ToString();
                treeNode.BackColor = Color.FromArgb(neuron.getCSVector().R, neuron.getCSVector().G, neuron.getCSVector().B);
                treeViewVertexList.Nodes.Add(treeNode);
                vernum++;
            }
        }

        private void glControl1_Load(object sender, EventArgs e)
        {
            loaded = true;
            GL.ClearColor(Color.FromArgb(255, 255, 192));
            GL.Enable(EnableCap.DepthTest);
            SetupViewport();
        }

        private void Application_Idle(object sender, EventArgs e)
        {
            while (glControl1.IsIdle)
            {
                angleX += 0.1f;
                glControl1.MakeCurrent();
                glControl1.Invalidate();
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            Application.Idle -= Application_Idle;
            base.OnClosing(e);
        }

        private void SetupViewport()
        {
            int w = glControl1.Width;
            int h = glControl1.Height;
            GL.Viewport(0, 0, w, h);
            GL.LoadIdentity();
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 3, w / (float)h, 1f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
            GL.MatrixMode(MatrixMode.Modelview);
        }

        public void Render()
        {

            Matrix4d mvMat = Matrix4d.LookAt(eye, target, up);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref mvMat);


            GL.Scale(distance, distance, distance);
            GL.Rotate(angleX, 0.0f, 1.0f, 0.0f);
            GL.Rotate(angleY, 1.0f, 0.0f, 0.0f);


            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            //GL.PushMatrix();
            //GL.Translate(0, -5, 0);
            //sofmnet.DrawGrid(Color.Black, 1f, 1f);
            //GL.PopMatrix();

            // Filled
            
            GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
            sofmnet.VisualizeSOM(Color.Blue);

            GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
            sofmnet.DrawPolyFrame(Color.Black);

            // Wireframe
            //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
        }

        private void glControl1_Paint(object sender, PaintEventArgs e)
        {
            if (!loaded)
                return;
            Render();
            glControl1.SwapBuffers();
        }

        private void glControl1_KeyDown(object sender, KeyEventArgs e)
        {
            if (!loaded) return;

            if (e.KeyCode == Keys.W)
            {
                angleY += 0.5f;
            }
            if (e.KeyCode == Keys.S)
            {
                angleY -= 0.5f;
            }

            if (e.KeyCode == Keys.A)
            {
                angleX += 0.5f;
                //eye.Y += 0.1f;
            }

            if (e.KeyCode == Keys.D)
            {
                angleX -= 0.5f;

            }

            if (e.KeyCode == Keys.Q)
            {
                distance += 0.05f;

            }

            if (e.KeyCode == Keys.E)
            {
                distance -= 0.05f;
            }
            glControl1.Invalidate();
        }

        private void glControl1_Resize(object sender, EventArgs e)
        {
            glControl1.MakeCurrent();
            SetupViewport();
        }

        private void glControl1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            System.Windows.Forms.MouseEventArgs ev = (e as System.Windows.Forms.MouseEventArgs);
            _mouseStartX = ev.X;
            _mouseStartY = ev.Y;
        }

        private void glControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            System.Windows.Forms.MouseEventArgs ev = (e as System.Windows.Forms.MouseEventArgs);

            angleXS = angleX;
            angleYS = angleY;
            distanceS = distance;

        }

        private void glControl1_MouseMove(object sender, EventArgs e)
        {
            System.Windows.Forms.MouseEventArgs ev = (e as System.Windows.Forms.MouseEventArgs);
            if (ev.Button == MouseButtons.Left)
            {
                angleX = angleXS + (ev.X - _mouseStartX) * rotSpeed;
                angleY = angleYS + (ev.Y - _mouseStartY) * rotSpeed;
            }
            if (ev.Button == MouseButtons.Right)
            {
                distance = Math.Max(5f, distanceS + (ev.Y - _mouseStartY) / 10.0f);
            }
            glControl1.Invalidate();
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            if (!animating)
            {
                animating = true;
                Application.Idle += Application_Idle;
            }
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            if (animating)
            {
                animating = false;
                Application.Idle -= Application_Idle;
            }
        }

        private void toolBtnZoomin_Click(object sender, EventArgs e)
        {
            distance += 0.1f;
            glControl1.Invalidate();
        }

        private void toolBtnZoomout_Click(object sender, EventArgs e)
        {
            distance -= 0.1f;
            glControl1.Invalidate();
        }

        private void userGuideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new GuideForm("mw");
        }

        private void treeViewSeqList_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            textBoxSeqID.Text = e.Node.Text;

            foreach (var cvector in sofmnet.CompositionalSpectrum.CSVectorList)
            {
                if (cvector.SequenceName.Equals(e.Node.Text))
                {
                    textBoxSeqRGB.Text = cvector.R + "," + cvector.G + "," + cvector.B;
                }
            }
        }

        private void treeViewSeqList_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }

        private void treeViewVertexList_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            textBoxVertexID.Text = e.Node.Text;
            textBoxVertexCoords.Text = this.sofmnet.NetworkNeuronList[Int32.Parse(e.Node.Name)].getNeuronCoordinates().ToString();
            int r = this.sofmnet.NetworkNeuronList[Int32.Parse(e.Node.Name)].getCSVector().R;
            int g = this.sofmnet.NetworkNeuronList[Int32.Parse(e.Node.Name)].getCSVector().G;
            int b = this.sofmnet.NetworkNeuronList[Int32.Parse(e.Node.Name)].getCSVector().B;
            textBoxVertexRGB.Text = r + "," + g + "," + b;
        }
    }
}
